<?php
/**
 * 
 * +------------------------------------------------------------+
 * @category Http 
 * +------------------------------------------------------------+
 * 模拟发送POST和GET请求
 * +------------------------------------------------------------+
 *
 * @author anzai <236049524@qq.com>
 * @copyright http://www.judianyun.com 2013
 * @version 1.0
 *
 * Modified at : 2013-11-1 13:45:44
 *
 */
class Http {
	/**
	 * 请求方法(POST和GET两种)
	 */
	public $method = 'GET';
	
	///cookie
	private $_cookie = '';
	
	///POST请求数据
	private $_post = '';
	
	///请求后响应的header信息
	private $_header = '';
	
	///默认提交类型
	private $_contentType =	'application/x-www-form-urlencoded';
	
	///请求结果得到的数据
	private $_data = '';
	
	///错误码
	private $_errno	= 0;
	
	///错误信息
	private $_errstr = '';
	
	///socket链接资源
	private $_fp = null;
	
	///发起请求
    private function _connect($host, $port = 80, $timeout = 30) {
        $this->_fp = fsockopen($host, $port, $errno, $errstr, $timeout);
        
        if (!$this->_fp) {
        	$this->_errno = $errno;
        	$this->_errstr = $errstr;
            return false;
        }
        
        return true;
    }
    
	///结束请求
    private function _disconnect() {
    	$res = true;
    	if ($this->_fp){
    		$res = fclose($this->_fp);
    		$this->_fp = null;
    	}
        return $res;
    }
    
    /**
     * 
     * +------------------------------------------------------------+
     * @name get
     * +------------------------------------------------------------+
     * 发送GET请求
     * +------------------------------------------------------------+
     *
	 * @param string	$url		请求URL地址
	 * @param string	$referer	请求前的URL地址
	 * @param integer	$timeout	超时时间（秒）
	 * @param boolean	$block		请求模式：true阻塞 false非阻塞
     *
     */
    public function get($url, $referer = '', $limit = 0, $timeout = 30, $block = TRUE) {
		$this->method = 'GET';
		return $this->request($url, $referer, $limit, $timeout, $block);
	}
	
	/**
	 * 获取cookie
	 */
	function getCookie() {
		$cookies = array();
		if(preg_match_all("|Set-Cookie: ([^;]*);|", $this->_header, $m)) {
			foreach($m[1] as $c) {
				list($k, $v) = explode('=', $c);
				$cookies[$k] = $v;
			}
		}
		
        return $cookies;
	}
	
	/**
	 * 获取错误码
	 */
	public function getErrno() {
		return $this->_errno;
	}
	
	/**
	 * 获取错误信息
	 */
	public function getError() {
		return $this->_errstr;
	}
	
	/**
	 * 获取请求后响应内容
	 */
	public function getData() {
		if (strpos($this->_header, 'chunk')) {
			$data = explode(chr(13), $this->_data);
			return $data[1];
		} else {
			return $this->_data;
		}
	}
	
	/**
	 * 获取请求后响应的Header信息
	 */
	public function getHeader(){
		return $this->_header;
	}
    
    /**
     * 获取Header中的status
     */
	public function getStatus() {
		preg_match("|^HTTP/1.1 ([0-9]{3}) (.*)|", $this->_header, $m);
		return array($m[1], $m[2]);
	}
	
	/**
	 * 
	 * +------------------------------------------------------------+
	 * @name post
	 * +------------------------------------------------------------+
	 * 发送POST请求
	 * +------------------------------------------------------------+
	 *
	 * @param string	$url		请求URL地址
	 * @param array		$data		POST请求数据
	 * @param string	$referer	请求前的URL地址
	 * @param integer	$timeout	超时时间（秒）
	 * @param boolean	$block		请求模式：true阻塞 false非阻塞
	 *
	 */
	public function post($url, $data = array(), $referer= '', $limit = 0, $timeout = 30, $block = TRUE){
		$this->method = 'POST';
		$this->_contentType = 'application/x-www-form-urlencoded';	
		if($data) {
			if (is_array($data)){
				$post = '';
				foreach($data as $k=>$v) {
					$post .= $k.'='.rawurlencode($v).'&';
				}
				$this->_post .= substr($post, 0, -1);
			}else{
				$this->_post = rawurlencode($data);
			}
		}
		
		return $this->request($url, $referer, $limit, $timeout, $block);
	}
	
	/**
	 * 
	 * +------------------------------------------------------------+
	 * @name request
	 * +------------------------------------------------------------+
	 * 发送请求
	 * +------------------------------------------------------------+
	 *
	 * @param string  $URI		请求链接
	 * @param string  $referer  请求前的URL地址
	 * @param integer $limit	每次读取最新字节数
	 * @param integer $timeout  超时时间（秒）
	 * @param boolean $block	请求模式：true阻塞 false非阻塞
	 *
	 */
	public function request($URI, $referer = '', $limit = 0, $timeout = 30, $block = true){
		$URI_PARTS = parse_url($URI);
		if (empty($URI_PARTS["query"]))
			$URI_PARTS["query"] = '';
		if (empty($URI_PARTS["path"]))
			$URI_PARTS["path"] = '';
		
		if($timeout > ini_get('max_execution_time')){
			@set_time_limit($timeout);
		}
		$method = strtoupper($this->method) == 'POST' ? 'POST' : 'GET';
		$path = $URI_PARTS['path'] ? $URI_PARTS['path'] . ($URI_PARTS['query'] ? '?' . $URI_PARTS['query'] : '') : '/';
		
		switch(strtolower($URI_PARTS["scheme"])){
			case 'http':
				$host = $URI_PARTS['host'];
				$port = $URI_PARTS['port'] ? $URI_PARTS['port'] : 80;
				break;
				
			case 'https':
				$host = 'ssl://' . $URI_PARTS['host'];
                $port = 443;
				break;
				
			default:
				return false;
		}
		//发起请求
		if ($this->_connect($host, $port, $timeout)){
			$out  = $method . " $path HTTP/1.1\r\n";
			$out .= "Accept: */*\r\n";
			$out .= "Referer: $referer\r\n";
			$out .= "Accept-Language: zh-cn\r\n";
			$out .= "User-Agent: " . $_SERVER['HTTP_USER_AGENT'] . "\r\n";
			$out .= "Host: $host\r\n";
			$out .= $this->cookie ? "Cookie: $this->cookie\r\n" : '';
			if($method == 'POST') {
				$out .= $this->_contentType ? 'Content-Type: ' . $this->_contentType . "\r\n" : '';
				$out .= 'Content-Length: ' . strlen($this->_post) . "\r\n";
				$out .= "Cache-Control: no-cache\r\n";
				$out .= "Connection: Close\r\n\r\n";
				$out .= $this->_post;
			} else {
				$out .= "Connection: Close\r\n\r\n";
			}
			
			stream_set_blocking($this->_fp, $block);
			stream_set_timeout($this->_fp, $timeout);
			fwrite($this->_fp, $out);
			
			$this->_data = '';
			$status = stream_get_meta_data($this->_fp);

			if(!$status['timed_out']) {
				$maxsize = min($limit, 1024000);
				if($maxsize == 0) $maxsize = 1024000;
				$start = false;
				while(!feof($this->_fp)) {
					if($start) {
						$line = fread($this->_fp, $maxsize);
						if(strlen($this->_data) > $maxsize) break;
						$this->_data .= $line;
					} else {
						$line = fgets($this->_fp);
						$this->_header .= $line;
						if($line == "\r\n" || $line == "\n") $start = true;
					}
				}
			}
			//关闭请求
			$this->_disconnect();
			if ($this->success()){
				return true;
			}else{
				return false;
			}
		}
		
		return false;
	}
	
	/**
	 * 判断是否有请求成功
	 */
	public function success(){
		$status = $this->getStatus();
		if(intval($status[0]) != 200) {
			$this->_errno = $status[0];
			$this->_errstr = $status[1];
			return false;
		}
		return true;
	}
	
	/**
	 * 
	 * +------------------------------------------------------------+
	 * @name setCookie
	 * +------------------------------------------------------------+
	 * 设置COOKIE，发起请求前设置
	 * +------------------------------------------------------------+
	 *
	 * @param string $name  键名
	 * @param string $value 内容
	 *
	 */
	function setCookie($name, $value) {
		$this->cookie .= "$name=$value;";
	}
}

?>